package com.platform.module.common.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;

@Configuration
@AutoConfigureAfter({RedisProperties.class})
public class RedisConfig {
    private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);

    @Resource
    private RedisProperties redisProperties;

    @Value("${spring.profiles.active}")
    private String environment;

    @Bean
    public RedisConnectionFactory jedisConnectionFactory() {
        if (this.environment.contains("pro")) {
            log.info("加载redis集群配置");
            return getClusterJedisConnectionFactory();
        }
        log.info("加载redis单机配置");
        return getSingleJedisConnectionFactory();
    }

    public JedisConnectionFactory getClusterJedisConnectionFactory() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(Integer.parseInt(this.redisProperties.getPoolMaxActive()));
        poolConfig.setMaxIdle(Integer.parseInt(this.redisProperties.getPoolMaxIdle()));
        poolConfig.setMaxWait(Duration.ofMillis(Long.parseLong(this.redisProperties.getPoolMaxWait())));
        poolConfig.setMinIdle(Integer.parseInt(this.redisProperties.getPoolMinIdle()));
        poolConfig.setTestOnBorrow(Boolean.parseBoolean(this.redisProperties.getTestOnBorrow()));
        return new JedisConnectionFactory(getRedisCluster(), poolConfig);
    }

    @Bean
    public RedisClusterConfiguration getRedisCluster() {
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(this.redisProperties.getNodes());
        redisClusterConfiguration.setMaxRedirects(Integer.parseInt(this.redisProperties.getMaxAttempts()));
        redisClusterConfiguration.setPassword(this.redisProperties.getPassword());
        return redisClusterConfiguration;
    }

    public JedisConnectionFactory getSingleJedisConnectionFactory() {

        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(this.redisProperties.getHost());
        config.setPort(Integer.parseInt(this.redisProperties.getPort()));
        config.setDatabase(Integer.parseInt(this.redisProperties.getDatabase()));
        config.setPassword(this.redisProperties.getPassword());
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder poolingConfig =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(Integer.parseInt(this.redisProperties.getPoolMaxActive()));
        poolConfig.setMaxIdle(Integer.parseInt(this.redisProperties.getPoolMaxIdle()));
        poolConfig.setMinIdle(Integer.parseInt(this.redisProperties.getPoolMinIdle()));
        poolConfig.setMaxWait(Duration.ofMillis(Long.parseLong(this.redisProperties.getPoolMaxWait())));
        poolConfig.setTestOnBorrow(Boolean.parseBoolean(this.redisProperties.getTestOnBorrow()));
        poolingConfig.poolConfig(poolConfig);
        return new JedisConnectionFactory(config, poolingConfig.build());
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        return stringRedisTemplate;
    }

}
